package my.netty.channel.nio;

import my.netty.channel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class NioEventLoop extends SingleThreadEventLoop {

    private static final Logger log = LoggerFactory.getLogger(NioEventLoop.class);

    private final SelectorProvider provider;
    private final Selector selector;

    public NioEventLoop(EventLoopGroup parent, ThreadFactory threadFactory) {
        super(parent, threadFactory);
        this.provider = SelectorProvider.provider();
        this.selector = openSelector();
    }

    private Selector openSelector() {
        try {
            return provider.openSelector();
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    public Selector selector() {
        return this.selector;
    }

    public void run() {
        while (true) {
            try {
                select();
                processSelectedKeys(selector.selectedKeys());
            } catch (Throwable e) {
                log.error("Work Failed", e);
            } finally {
                runAllTasks();
            }
        }
    }

    private void select() throws IOException {
        Selector selector = this.selector;
        for (;;){
            log.info("线程[{}]等待任务。。。。。。。", Thread.currentThread().getName());
            int selectedKeys = selector.select(3000);
            if (selectedKeys != 0 || hasTasks()) {
                break;
            }
        }
    }

    private void processSelectedKeys(Set<SelectionKey> selectedKeys) throws IOException {
        if (selectedKeys.isEmpty()) {
            return;
        }
        Iterator<SelectionKey> iterator = selectedKeys.iterator();
        do {
            SelectionKey key = iterator.next();
            iterator.remove();
            processSelectedKey(key);
        } while (iterator.hasNext());
    }

    private void processSelectedKey(SelectionKey key) throws IOException {
        if (key.isAcceptable()) {
            ((ServerChannel) key.attachment()).accept();
        } else if (key.isReadable()) {
            ByteBuffer buff = ByteBuffer.allocate(1024);
            SocketChannel channel = (SocketChannel) key.channel();
            int len;
            try {
                len = channel.read(buff);
            } catch (Throwable e) {
                log.error("客户群读取错误", e);
                channel.close();
                return;
            }
            if (len == -1) {
                log.info("关闭客户端");
                channel.close();
                return;
            }
            ((Channel) key.attachment()).pipeline().fireChannelRead(buff);
        }
    }

    @Override
    public void shutdownGracefully() {

    }

    @Override
    public boolean isTerminated() {
        return false;
    }

    @Override
    public void awaitTermination(Integer integer, TimeUnit timeUnit) throws InterruptedException {

    }

    @Override
    protected void register0(Channel channel) {
        channel.register(this);
    }

    @Override
    public EventLoop next() {
        return this;
    }
}
